
#include "DXUT.h"
#include "Block.h"
#include "Chunk.h"

#ifdef DEFERRED_UPDATE
SRWLOCK					DEFERRED_LOCK;
#endif

/* Blockdefines */
const Block SKY_BLOCK			=  {AIR, 15, 0, 0, 0};
const Block AIR_BLOCK			=  {AIR, 0, 0, 0, 0};
const Block DIRT_BLOCK			=  {1, 0, 0, 0, SOLID};
const Block GRASS_BLOCK			=  {2, 0, 0, 0, SOLID};
const Block SNOWYGRASS_BLOCK	=  {2, 0, 0, 1, SOLID};
const Block STONE_BLOCK			=  {3, 0, 0, 0, SOLID};
const Block COBBLE_BLOCK		=  {4, 0, 0, 0, SOLID};
const Block COAL_BLOCK			=  {5, 0, 0, 0, SOLID};
const Block IRON_ORE_BLOCK		=  {6, 0, 0, 0, SOLID};
const Block GOLD_ORE_BLOCK		=  {7, 0, 0, 0, SOLID};
const Block DIAMAND_ORE_BLOCK	=  {8, 0, 0, 0, SOLID};
const Block REDSTONE_ORE_BLOCK	=  {9, 0, 0, 0, SOLID};
const Block WOOD_BLOCK			=  {10, 0, 0, 0x00, SOLID};
const Block DARKWOOD_BLOCK		=  {10, 0, 0, 0x01, SOLID};
const Block BIRCHWOOD_BLOCK		=  {10, 0, 0, 0x02, SOLID};
const Block REDWOOD_BLOCK		=  {10, 0, 0, 0x03, SOLID};

const Block LEAF_BLOCK			=  {14, 0, 0, 0x0F, 2};
const Block DARKLEAF_BLOCK		=  {14, 0, 0, 0x1F, 3};
const Block REDLEAF_BLOCK		=  {14, 0, 0, 0x2F, 3};
const Block TALLGRASS_BLOCK		=  {15, 0, 0, 0x0, 0};
const Block GLOWSTONE_BLOCK		=  {16, 0, 0xF, 0, SOLID};
const Block REED_BLOCK			=  {17, 0, 0, 0, 0}; 
const Block CACTUS_BLOCK		=  {18, 0, 0, 0, 0};

const Block SAND_BLOCK			=  {20, 0, 0, 0, SOLID};

const Block TORCH				=  {40, 0, 0xE, 0, 0};

const Block REDSTONE_DUST		=  {90, 0, 0, 0, 0};
const Block REDSTONE_TORCH		=  {91, 0, 0x7, 0, 0};//AKTIV, POWERED};

const Block STILLWATER_BLOCK	=  {WATER, 0, 0, 0xFF, 1 | LIQUID};

const Block STILLLAVA_BLOCK		=  {LAVA, 0, 0xF, 0xFF, 1 | LIQUID};

const Block VOID_BLOCK			=  {LEER, 0, 0, 0, SOLID};
/* Blockdefines */

#ifdef RENDER

INT Block::Generate(byte blockID, int x, int z, int y, float px, float pz, float py, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	auto it = generationMap.find(blockID);
	if (it != generationMap.end()) {				
		return  it->second(x, z, y, px, pz, py, pBuffer, pVertex, pSize);
	} else {
		return -1;
	}
};

INT Block::Generate(BlockVertex * pVertex, WORD * pSize) const {
	auto git = geometryMap.find(blockID);
	if (git != geometryMap.end()) {
		memcpy(pVertex, git->second.first, git->second.second * sizeof(BlockVertex));
		*pSize = git->second.second;
		return 0;
	} else {
		int result = -1;
		auto it = generationMap.find(blockID);
		if (it != generationMap.end()) {	
			genBuffer * pBuffer = (genBuffer*)   calloc(5832, sizeof(genBuffer)); 
			genBuffer buf = SKY_BLOCK.toBuffer();
			for (int i = 0; i < 5832; i++)
				pBuffer[i] = buf;
			pBuffer[343] = toBuffer();
			result = it->second(1, 1, 1, 0.0f, 0.0f, 0.0f, pBuffer, pVertex, pSize);
			free(pBuffer);
		} else {
			D3DXVECTOR2 * uv  = getBlockUV(blockID, FACELEFT);
			D3DXVECTOR2 * uv2 = getBlockUV(blockID, FACEUP);

			BlockVertex vertex[24] = {
				{D3DXVECTOR3( -0.5f, -0.5f, -0.5f), uv[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f, -0.5f,  0.5f), uv[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},			
				{D3DXVECTOR3( -0.5f,  0.5f, -0.5f), uv[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f,  0.5f,  0.5f), uv[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},

				{D3DXVECTOR3(  0.5f,  0.5f,  0.5f), uv[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f,  0.5f), uv[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},			
				{D3DXVECTOR3(  0.5f,  0.5f, -0.5f), uv[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f, -0.5f), uv[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},

				{D3DXVECTOR3(  0.5f,  0.5f, -0.5f),	uv[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f, -0.5f),	uv[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f,  0.5f, -0.5f),	uv[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f, -0.5f, -0.5f),	uv[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},

				{D3DXVECTOR3( -0.5f, -0.5f,  0.5f),	uv[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f,  0.5f),	uv[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f,  0.5f,  0.5f),	uv[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f,  0.5f,  0.5f),	uv[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},

				{D3DXVECTOR3( -0.5f, -0.5f, -0.5f),	uv[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f, -0.5f),	uv[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},			
				{D3DXVECTOR3( -0.5f, -0.5f,  0.5f),	uv[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f, -0.5f,  0.5f),	uv[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},

				{D3DXVECTOR3(  0.5f,  0.5f,  0.5f),	uv2[3], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3(  0.5f,  0.5f, -0.5f),	uv2[1], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},			
				{D3DXVECTOR3( -0.5f,  0.5f,  0.5f),	uv2[2], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
				{D3DXVECTOR3( -0.5f,  0.5f, -0.5f),	uv2[0], 1.0f, 0.0f, D3DXVECTOR3(0.3f, 1.0f, 0.4f)},
			};
			memcpy(pVertex, vertex, 24 * sizeof(BlockVertex));
			*pSize = 24;
		}
		blocktype id = blockID;
		WORD size = *pSize;
		BlockVertex * buffer = (BlockVertex*) malloc(sizeof(BlockVertex) * size);
		memcpy(buffer, pVertex, sizeof(BlockVertex) * size);
		geometryMap.insert(pair<blocktype,BLOCKGEO>(id, BLOCKGEO(buffer, size)));
		return result;
	}
};

INT Block::GenerateIndexed(BlockVertex ** pVertex, WORD * pVSize, WORD ** pIndex, WORD * pISize ) const {
	if (pVertex && pIndex) {
		*pVertex = (BlockVertex*) malloc(sizeof(BlockVertex) * 48);
		Generate(*pVertex, pVSize);

		WORD size	= *pVSize;
		WORD i		= 0;
		WORD k		= 0;
		*pISize		= 6 * (size / 4);
		*pIndex		= (WORD*) malloc(6 * (size / 4) * sizeof(WORD));
		while (size >= 4) {
			(*pIndex)[k + 0] = 0 + i;
			(*pIndex)[k + 1] = 1 + i;
			(*pIndex)[k + 2] = 2 + i;

			(*pIndex)[k + 3] = 2 + i;
			(*pIndex)[k + 4] = 1 + i;
			(*pIndex)[k + 5] = 3 + i;

			size	-= 4;
			i		+= 4;
			k		+= 6;
		}
		return 0;
	} else{
		return -1;
	}
}

#endif

BYTE Block::Update(int * px, int * pz, int * py, IWorld * world, byte updateType, byte * ticks) {
	auto it = updateMap.find(blockID);
	if ((it != updateMap.end()) || ((status & SOLID) && ((it = updateMap.find(254)) != updateMap.end()))) {
		return it->second(px, pz, py, world, *this, updateType, ticks);
	} else {
		return 0;
	}
};

Block IWorld::getBlock(D3DXVECTOR3 pos) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	return getBlock(bx, bz, by);
};

Block * IWorld::getpBlock(D3DXVECTOR3 pos) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	return getpBlock(bx, bz, by);
};

void IWorld::setBlock(D3DXVECTOR3 pos, Block block, byte flags) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	setBlock(bx, bz, by, block, flags);
};

Block IWorld::breakBlock(D3DXVECTOR3 pos) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	return breakBlock(bx, bz, by);
};

byte IWorld::updateBlock(D3DXVECTOR3 pos, byte type, byte * ticks) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	return updateBlock(bx, bz, by, type, ticks);
};

void IWorld::delayedUpdateBlock(D3DXVECTOR3 pos, byte type, byte ticks) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	delayedUpdateBlock(bx, bz, by, type, ticks);
};

#ifdef RENDER	
void IWorld::setDirty(D3DXVECTOR3 pos, bool immediatly) {
	int bx = static_cast<int>(floor(pos.x + 0.5f)); 
	int by = static_cast<int>(floor(pos.y + 0.5f)); 
	int bz = static_cast<int>(floor(pos.z + 0.5f));
	setDirty(bx, bz, by, immediatly);
};
#endif

bool IWorld::ray(const D3DXVECTOR3 * eye, const D3DXVECTOR3 * dir, D3DXVECTOR3 * outCoord, Block * outBlock, bool placementRay, BYTE * facing) {	
	D3DXVECTOR3 nDir;
	D3DXVec3Normalize(&nDir, dir);
	D3DXVec3Scale(&nDir, &nDir, 0.01f);
	D3DXVec3Add(outCoord,eye,&nDir);

	int max_distance = 4000;

	int x = 0;//static_cast<int>(floor(outCoord->x + 0.5f));
	int y = -1;//static_cast<int>(floor(outCoord->y + 0.5f));
	int z = 0;//static_cast<int>(floor(outCoord->z + 0.5f));

	while (max_distance--) {
		int bx = static_cast<int>(floor(outCoord->x + 0.5f)); 
		int by = static_cast<int>(floor(outCoord->y + 0.5f)); 
		int bz = static_cast<int>(floor(outCoord->z + 0.5f));
		/* if Block is actually new */
		if ((x != bx) || (y != by) || (z != bz)) {
			x = bx; y = by; z = bz;
			Block block = getBlock(x, z, y);
			if ((block.blockID != AIR) && (block.blockID != LEER) && !(block.status & LIQUID)) {
				if (placementRay) {
					D3DXVec3Subtract(outCoord,outCoord,&nDir);
				}
				outCoord->x = floor(outCoord->x + 0.5f);
				outCoord->y = floor(outCoord->y + 0.5f);
				outCoord->z = floor(outCoord->z + 0.5f);
				if (facing) {
					INTVECTOR3 dif = INTVECTOR3(
						bx - static_cast<int>(outCoord->x),
						bz - static_cast<int>(outCoord->z), 
						by - static_cast<int>(outCoord->y)						
						);
					if (dif.x > 0)
						*facing = FACELEFT;
					else if (dif.x < 0)
						*facing = FACERIGHT;
					else if (dif.y > 0)
						*facing = FACEDOWN;
					else if (dif.y < 0)
						*facing = FACEUP;
					else if (dif.z > 0)
						*facing = FACEBACK;
					else if (dif.z < 0)
						*facing = FACEFRONT;
				}
				outBlock = &block;
				return true; 
			}
		}
		D3DXVec3Add(outCoord,outCoord,&nDir);
	}
	return false;
};

void blockUpdate(IWorld * world, DWORD random, Block block, int x, int z, int y) {
	Block topBlock = world->getBlock(x,z,y+1);
	Block leftBlock;
	Block rightBlock;
	Block frontBlock;
	Block backBlock;
	Block downBlock;
	switch(block.blockID) {
	case 1: /* Dirt */
		if ((!(topBlock.status & SOLID) && (random % 128) == 0) && (max(topBlock.blockLight, topBlock.skyLight) > 7)) {
			if ((world->getBlock(x+1,z,y).blockID == 2) || (world->getBlock(x-1,z,y).blockID == 2) || 
				(world->getBlock(x,z+1,y).blockID == 2) || (world->getBlock(x,z-1,y).blockID == 2) || 
				(world->getBlock(x+1,z+1,y).blockID == 2) || (world->getBlock(x-1,z+1,y).blockID == 2) || 
				(world->getBlock(x-1,z+1,y).blockID == 2) || (world->getBlock(x-1,z-1,y).blockID == 2) ||

				(world->getBlock(x+1,z,y-1).blockID == 2) || (world->getBlock(x-1,z,y-1).blockID == 2) || 
				(world->getBlock(x,z+1,y-1).blockID == 2) || (world->getBlock(x,z-1,y-1).blockID == 2) || 
				(world->getBlock(x+1,z+1,y-1).blockID == 2) || (world->getBlock(x-1,z+1,y-1).blockID == 2) || 
				(world->getBlock(x-1,z+1,y-1).blockID == 2) || (world->getBlock(x-1,z-1,y-1).blockID == 2) ||

				(world->getBlock(x+1,z,y+1).blockID == 2) || (world->getBlock(x-1,z,y+1).blockID == 2) || 
				(world->getBlock(x,z+1,y+1).blockID == 2) || (world->getBlock(x,z-1,y+1).blockID == 2) || 
				(world->getBlock(x+1,z+1,y+1).blockID == 2) || (world->getBlock(x-1,z+1,y+1).blockID == 2) || 
				(world->getBlock(x-1,z+1,y+1).blockID == 2) || (world->getBlock(x-1,z-1,y+1).blockID == 2))
				world->setBlock(x, z, y, GRASS_BLOCK, UPDATE_GEOMETRY);
		}
		break;
	case 2: /* Grass */
		if ((topBlock.status & SOLID) || ((topBlock.status & LIQUID) && (max(topBlock.skyLight,topBlock.blockLight) < 10))) {
			world->setBlock(x, z, y, DIRT_BLOCK, UPDATE_GEOMETRY);
		}
		break;
	case 9: /* Redstoneore */
		if (block.metadata == 1) {
			world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
			break;
		}
		leftBlock = world->getBlock(x+1,z,y);
		rightBlock = world->getBlock(x-1,z,y);
		frontBlock = world->getBlock(x,z+1,y);
		backBlock = world->getBlock(x,z-1,y);
		downBlock = world->getBlock(x,z,y-1);
		if ((leftBlock.blockID != 9) && (leftBlock.blockID != 0)) world->setBlock(x+1, z, y, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		if ((rightBlock.blockID != 9) && (rightBlock.blockID != 0)) world->setBlock(x-1, z, y, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		if ((frontBlock.blockID != 9) && (frontBlock.blockID != 0)) world->setBlock(x, z+1, y, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		if ((backBlock.blockID != 9) && (backBlock.blockID != 0)) world->setBlock(x, z-1, y, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		if ((topBlock.blockID != 9) && (topBlock.blockID != 0)) world->setBlock(x, z, y+1, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		if ((downBlock.blockID != 9) && (downBlock.blockID != 0)) world->setBlock(x, z, y-1, REDSTONE_ORE_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		block.metadata = 1;
		world->setBlock(x, z, y, block);
		break;
	case 10: /* Wood */
		//world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		break;
	case 14: /* Leaf */
		leftBlock = world->getBlock(x+1,z,y);
		rightBlock = world->getBlock(x-1,z,y);
		frontBlock = world->getBlock(x,z+1,y);
		backBlock = world->getBlock(x,z-1,y);
		downBlock = world->getBlock(x,z,y-1);
		if ((leftBlock.blockID == 10) || (rightBlock.blockID == 10) || (frontBlock.blockID == 10) ||
			(backBlock.blockID == 10) || (topBlock.blockID == 10) || (downBlock.blockID == 10)) {
				if (block.metadata != 4) {
					block.metadata = 4;
					world->setBlock(x, z, y, block);
				}
		} else {
			byte vitality = 0;
			if (leftBlock.blockID == 14) vitality	= max(vitality, leftBlock.metadata);
			if (rightBlock.blockID == 14) vitality	= max(vitality, rightBlock.metadata);
			if (frontBlock.blockID == 14) vitality	= max(vitality, frontBlock.metadata);
			if (backBlock.blockID == 14) vitality	= max(vitality, backBlock.metadata);
			if (topBlock.blockID == 14) vitality	= max(vitality, topBlock.metadata);
			if (downBlock.blockID == 14) vitality	= max(vitality, downBlock.metadata);

			if (vitality >= block.metadata) {
				if (vitality > 0) {
					block.metadata = vitality - 1;
				}
			} else {
				block.metadata = vitality;
			}

			if (block.metadata == 0) {
				world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
			} else {
				world->setBlock(x, z, y, block);
			}
		}
		break;
	case WATER: /* Water */
		/*
		downBlock = world->getBlock(x,z,y-1);
		if (downBlock.blockID==AIR)
		{
		int drain = 2;
		if (block.metadata<=drain)
		{
		drain = block.metadata;
		world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		}
		else
		{
		block.metadata-=drain;
		world->setBlock(x, z, y, block , UPDATE_GEOMETRY | UPDATE_LIGHT);
		}
		Block newblock = {WATER, 0, 0, drain, 1 | LIQUID};
		world->setBlock(x, z, y-1, newblock, UPDATE_GEOMETRY | UPDATE_LIGHT);
		}
		else if (downBlock.blockID==WATER && downBlock.metadata<16)
		{
		int drain = 2;
		if (downBlock.metadata>14) drain = 16-downBlock.metadata;
		if (block.metadata<=drain)
		{
		drain = block.metadata;
		world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		break;
		}
		else
		{
		block.metadata-=drain;
		world->setBlock(x, z, y, block , UPDATE_GEOMETRY | UPDATE_LIGHT);
		}
		downBlock.metadata+=drain;
		world->setBlock(x, z, y-1, downBlock, UPDATE_GEOMETRY | UPDATE_LIGHT);
		}
		for (int i = 0; i < 4; i++)
		{
		int x2=x; int y2=y; int z2=z;
		switch (i)
		{
		case 0: x2++; break;
		case 1: x2--; break;
		case 2: z2++; break;
		case 3: z2--; break;
		}
		updateWaterSidewards(world, block, world->getBlock(x2,z2,y2),x,z,y,x2,z2,y2);
		block = world->getBlock(x,z,y);
		if (block.metadata < 2) break;
		}
		if (block.metadata < 2 && (rand() % 32 == 0))
		world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		*/
		break;
	}



};

#ifdef RENDER
/* BLOCK GENERATION SECTION */
inline int coord(int x, int z, int y) {
	return x + z * 18 + y * 324;
}

inline void calcLight(genBuffer ml, genBuffer l1, genBuffer l2, genBuffer dl, float * s, float * b) {
#if FALSE
	*b	= g_LightLevels[ml.blocklight];
	*s	= g_LightLevels[ml.skylight];
#else
	float bl	= g_LightLevels[ml.blocklight];
	float sl	= g_LightLevels[ml.skylight];
	float c		= 1.0f;

	if (l1.face) {
		bl += g_LightLevels[l1.blocklight];
		sl += g_LightLevels[l1.skylight];
		c += 1.0f;
	}
	if (l2.face) {
		bl += g_LightLevels[l2.blocklight];
		sl += g_LightLevels[l2.skylight];
		c += 1.0f;
	}
	if (dl.face && (l1.face || l2.face)) {
		bl += g_LightLevels[dl.blocklight];
		sl += g_LightLevels[dl.skylight];
		c += 1.0f;
	} 

	bl /= c;
	sl /= c;

	if (!l1.face | !l2.face | !dl.face) { bl *= 0.6f; sl *= 0.6f; }

	*b = bl;
	*s = sl;
#endif
}
void genLight(int x, int z, int y, char facing, genBuffer * buffer, float * c, float * b) {
	if (facing  & (FACELEFT | FACERIGHT)) {
		/* LEFT / RIGH */
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x, z - 1, y)], 
			buffer[coord(x, z, y - 1)] , 
			buffer[coord(x, z - 1, y - 1)], 
			&c[0],
			&b[0]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x, z + 1, y)], 
			buffer[coord(x, z, y - 1)] , 
			buffer[coord(x, z + 1, y - 1)], 
			&c[1],
			&b[1]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x, z - 1, y)], 
			buffer[coord(x, z, y + 1)] , 
			buffer[coord(x, z - 1, y + 1)], 
			&c[2],
			&b[2]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x, z + 1, y)], 
			buffer[coord(x, z, y + 1)] , 
			buffer[coord(x, z + 1, y + 1)], 
			&c[3],
			&b[3]);
	} else if (facing  & (FACEFRONT | FACEBACK)) {
		/* FRONT / BACK */
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x - 1, z, y)], 
			buffer[coord(x, z, y - 1)] , 
			buffer[coord(x - 1, z, y - 1)], 
			&c[0],
			&b[0]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x + 1, z, y)], 
			buffer[coord(x, z, y - 1)] , 
			buffer[coord(x + 1, z, y - 1)], 
			&c[1],
			&b[1]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x - 1, z, y)], 
			buffer[coord(x, z, y + 1)] , 
			buffer[coord(x - 1, z, y + 1)], 
			&c[2],
			&b[2]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x + 1, z, y)], 
			buffer[coord(x, z, y + 1)] , 
			buffer[coord(x + 1, z, y + 1)], 
			&c[3],
			&b[3]);
	} else if (facing  & (FACEDOWN | FACEUP)) {
		/* DOWN / UP */
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x - 1, z, y)], 
			buffer[coord(x, z - 1, y)] , 
			buffer[coord(x - 1, z - 1, y)], 
			&c[0],
			&b[0]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x + 1, z, y)], 
			buffer[coord(x, z - 1, y)] , 
			buffer[coord(x + 1, z - 1, y)], 
			&c[1],
			&b[1]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x - 1, z, y)], 
			buffer[coord(x, z + 1, y)] , 
			buffer[coord(x - 1, z + 1, y)], 
			&c[2],
			&b[2]);
		calcLight(buffer[coord(x, z, y)], 
			buffer[coord(x + 1, z, y)], 
			buffer[coord(x, z + 1, y)] , 
			buffer[coord(x + 1, z + 1, y)], 
			&c[3],
			&b[3]);
	}
}

const UINT	TEXTURESIZE = 512;
const float	TEXTURETILE = 1.0f / 16.0f;

D3DXVECTOR2 * __fastcall getBlockUV(char blockID, char faceing, byte meta) {
	D3DXVECTOR2 uv[4];
	switch (blockID) {
	case 1:  /* Dirt */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*2,	0.0f*0);
		uv[3] = D3DXVECTOR2(TEXTURETILE*3,	0.0f*0);
		uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*1);
		uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*1);
		break;
	case 2:  /* Grass */
		if (meta != 0) {
			if (faceing == FACEUP) {
				uv[2] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*4);
				uv[3] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*4);
				uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*5);
				uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*5);
			} else if (faceing == FACEDOWN) {
				uv[2] = D3DXVECTOR2(TEXTURETILE*2,	0.0f);
				uv[3] = D3DXVECTOR2(TEXTURETILE*3,	0.0f);
				uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE);
				uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE);
			} else {
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*4);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*4);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*5);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*5);
			}
		} else {
			if (faceing == FACEUP) {
				uv[2] = D3DXVECTOR2(0.0f,			0.0f);
				uv[3] = D3DXVECTOR2(TEXTURETILE,	0.0f);
				uv[0] = D3DXVECTOR2(0.0f,			TEXTURETILE);
				uv[1] = D3DXVECTOR2(TEXTURETILE,	TEXTURETILE);
			} else if (faceing == FACEDOWN) {
				uv[2] = D3DXVECTOR2(TEXTURETILE*2,	0.0f);
				uv[3] = D3DXVECTOR2(TEXTURETILE*3,	0.0f);
				uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE);
				uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE);
			} else {
				uv[2] = D3DXVECTOR2(TEXTURETILE*3,	0.0f);
				uv[3] = D3DXVECTOR2(TEXTURETILE*4,	0.0f);
				uv[0] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE);
				uv[1] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE);
			}
		}
		break;  
	case 3:  /* Stone */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*1,	0.0f);
		uv[3] = D3DXVECTOR2(TEXTURETILE*2,	0.0f);
		uv[0] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE);
		uv[1] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE);
		break;
	case 4:  /* Cubble */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*0,	TEXTURETILE*1);
		uv[3] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*1);
		uv[0] = D3DXVECTOR2(TEXTURETILE*0,	TEXTURETILE*2);
		uv[1] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*2);
		break;
	case 5:  /* Coal */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*2);
		uv[3] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*2);
		uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*3);
		uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*3);
		break;
	case 6:  /* Iron */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*2);
		uv[3] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*2);
		uv[0] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*3);
		uv[1] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*3);
		break;
	case 7:  /* Gold */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*0,	TEXTURETILE*2);
		uv[3] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*2);
		uv[0] = D3DXVECTOR2(TEXTURETILE*0,	TEXTURETILE*3);
		uv[1] = D3DXVECTOR2(TEXTURETILE*1,	TEXTURETILE*3);
		break;
	case 8:  /* Diamand */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*3);
		uv[3] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*3);
		uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*4);
		uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*4);
		break;
	case 9:  /* Redstone */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*3);
		uv[3] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*3);
		uv[0] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*4);
		uv[1] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*4);
		break;
	case 10:  /* Wood */
		if (faceing == FACEUP) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*1);
			uv[3] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*1);
			uv[0] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*2);
			uv[1] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*2);
		} else if (faceing == FACEDOWN) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*1);
			uv[3] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*1);
			uv[0] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*2);
			uv[1] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*2);
		} else {
			switch (meta)
			{
			case 0:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*1);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*1);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*2);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*2);
				break;
			case 1:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*7);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*7);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*8);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*8);
				break;
			case 2:
				uv[2] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*7);
				uv[3] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*7);
				uv[0] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*8);
				uv[1] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*8);
				break;
			case 3:
				uv[2] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*9);
				uv[3] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*9);
				uv[0] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*10);
				uv[1] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*10);
				break;
			default:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*1);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*1);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*2);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*2);
				break;
			}
		}
		break;  
	case 14:  /* Leaf */ 
		{
			BYTE metaHi = meta >> 4;
			switch (metaHi)
			{
			case 0:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*3);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*3);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*4);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*4);
				break;
			case 1:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*8);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*8);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*9);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*9);
				break;
			case 2:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*12);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*12);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*13);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*13);
				break;
			default:
				uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*3);
				uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*3);
				uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*4);
				uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*4);
				break;
			}
		}
		break;
	case 15:  /* Tall Grass */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*2);
		uv[3] = D3DXVECTOR2(TEXTURETILE*8,	TEXTURETILE*2);
		uv[0] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*3);
		uv[1] = D3DXVECTOR2(TEXTURETILE*8,	TEXTURETILE*3);
		break;
	case 16:  /* Glowstone */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*6);
		uv[3] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*6);
		uv[0] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*7);
		uv[1] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*7);
		break;
	case 17:  /* Reed */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*4);
		uv[3] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*4);
		uv[0] = D3DXVECTOR2(TEXTURETILE*9,	TEXTURETILE*5);
		uv[1] = D3DXVECTOR2(TEXTURETILE*10,	TEXTURETILE*5);
		break;
	case 18:  /* Cactus */
		if (faceing == FACEUP) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*4);
			uv[3] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*4);
			uv[0] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*5);
			uv[1] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*5);
		} else if (faceing == FACEDOWN) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*4);
			uv[3] = D3DXVECTOR2(TEXTURETILE*8,	TEXTURETILE*4);
			uv[0] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*5);
			uv[1] = D3DXVECTOR2(TEXTURETILE*8,	TEXTURETILE*5);
		} else {
			uv[2] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*4);
			uv[3] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*4);
			uv[0] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*5);
			uv[1] = D3DXVECTOR2(TEXTURETILE*7,	TEXTURETILE*5);
		}
		break;  
	case 20:  /* Sand */ 
		uv[2] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*1);
		uv[3] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*1);
		uv[0] = D3DXVECTOR2(TEXTURETILE*2,	TEXTURETILE*2);
		uv[1] = D3DXVECTOR2(TEXTURETILE*3,	TEXTURETILE*2);
		break;
	case 40:  /* Torch */ 
		if (faceing == FACEUP) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*5.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*5.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*5.5f);
			uv[1] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*5.5f);
		} else if (faceing == FACEDOWN) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*5.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*5.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*5.5f);
			uv[1] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*5.5f);
		} else {
			uv[2] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*5.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*5.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*0.4375f,	TEXTURETILE*6);
			uv[1] = D3DXVECTOR2(TEXTURETILE*0.5625f,	TEXTURETILE*6);
		}
		break;
	case 90:  /* Redstonedust */ 
		if (faceing == FACEUP) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*10);
			uv[3] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*10);
			uv[0] = D3DXVECTOR2(TEXTURETILE*4,	TEXTURETILE*11);
			uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*11);
		} else {
			uv[0] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*10);
			uv[2] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*10);
			uv[1] = D3DXVECTOR2(TEXTURETILE*5,	TEXTURETILE*11);
			uv[3] = D3DXVECTOR2(TEXTURETILE*6,	TEXTURETILE*11);
		}
		break;
	case 91:  /* Redstone Torch */ 
		if (faceing == FACEUP) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*6.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*6.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*6.5f);
			uv[1] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*6.5f);
		} else if (faceing == FACEDOWN) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*6.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*6.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*6.5f);
			uv[1] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*6.5f);
		} else {
			uv[2] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*6.375f);
			uv[3] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*6.375f);
			uv[0] = D3DXVECTOR2(TEXTURETILE*3.4375f,	TEXTURETILE*7);
			uv[1] = D3DXVECTOR2(TEXTURETILE*3.5625f,	TEXTURETILE*7);
		}
		break;
	case 100:  /* Water */ 
		if ((faceing == FACEUP) || (faceing == FACEDOWN)) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*12);
			uv[3] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*12);
			uv[0] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*13);
			uv[1] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*13);
		} else {
			uv[0] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*12);
			uv[2] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*12);
			uv[1] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*13);
			uv[3] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*13);
		}
		break;
	case 102:  /* Lava */ 
		if ((faceing == FACEUP) || (faceing == FACEDOWN)) {
			uv[2] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*14);
			uv[3] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*14);
			uv[0] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*15);
			uv[1] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*15);
		} else {
			uv[0] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*14);
			uv[2] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*14);
			uv[1] = D3DXVECTOR2(TEXTURETILE*13,	TEXTURETILE*15);
			uv[3] = D3DXVECTOR2(TEXTURETILE*14,	TEXTURETILE*15);
		}
		break;
	default:
		uv[2] = D3DXVECTOR2(0.0f,			0.0f);
		uv[3] = D3DXVECTOR2(TEXTURETILE,	0.0f);
		uv[0] = D3DXVECTOR2(0.0f,			TEXTURETILE);
		uv[1] = D3DXVECTOR2(TEXTURETILE,	TEXTURETILE);
		break;  
	}
	return uv;
};

byte genRedstonedust(int x, int z, int y, float _x, float _z, float _y, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	/* LIGHTVALUES */
	float skylight[4] = {
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
	};
	float blocklight[4] = {
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
	};

	byte bid = pBuffer[coord(x, z, y)].id;

	/*
	-x
	+-+---------+-+
	-z|0|         |1|
	+-+---------+-+
	| |         | |
	| |         | |
	| |         | |
	| |         | |
	+-+---------+-+
	|2|         |3|+z
	+-+---------+-+
	+x
	*/

	WORD size = 0;

	D3DXVECTOR2 * uv = getBlockUV(bid, FACEUP);

	float meta = static_cast<float>(pBuffer[coord(x, z, y)].metadata);
	D3DXVECTOR3 red		= D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	D3DXVECTOR3 yellow	= D3DXVECTOR3(0.0f, 0.2f, 0.0f);
	D3DXVECTOR3 color	= red * (meta / 15.0f) + yellow *  (max(0.0f, meta - 8.0f)  / 7.0f);

	/* DOWN */
	BlockVertex face[] = 
	{
		{D3DXVECTOR3( 0.5f + _x, -0.45f + _y,  0.5f + _z), uv[3], skylight[3], blocklight[3], color},
		{D3DXVECTOR3( 0.5f + _x, -0.45f + _y, -0.5f + _z), uv[1], skylight[1], blocklight[1], color},
		{D3DXVECTOR3(-0.5f + _x, -0.45f + _y,  0.5f + _z), uv[2], skylight[2], blocklight[2], color},
		{D3DXVECTOR3(-0.5f + _x, -0.45f + _y, -0.5f + _z), uv[0], skylight[0], blocklight[0], color},
	};

	memcpy(pVertex + size, face, sizeof(face));
	size += 4;
	/* DOWN */

	if (pBuffer[coord(x, z, y+1)].face) {
		uv = getBlockUV(bid, FACELEFT);
		if (pBuffer[coord(x+1, z, y+1)].id == bid) {
			D3DXVECTOR3 colorUp	= red * (pBuffer[coord(x+1, z, y+1)].metadata / 15.0f) + yellow *  (max(0.0f, pBuffer[coord(x+1, z, y+1)].metadata - 8.0f)  / 7.0f);
			BlockVertex face[] = 
			{
				{D3DXVECTOR3( 0.49f + _x, -0.5f + _y,  0.5f + _z),	uv[3], skylight[3], blocklight[3], color},
				{D3DXVECTOR3( 0.49f + _x,  0.5f + _y,  0.5f + _z),	uv[1], skylight[1], blocklight[1], colorUp},
				{D3DXVECTOR3( 0.49f + _x, -0.5f + _y, -0.5f + _z),	uv[2], skylight[2], blocklight[2], color},
				{D3DXVECTOR3( 0.49f + _x,  0.5f + _y, -0.5f + _z),	uv[0], skylight[0], blocklight[0], colorUp},
			};

			memcpy(pVertex + size, face, sizeof(face));
			size += 4;
		}

		if (pBuffer[coord(x-1, z, y+1)].id == bid) {
			D3DXVECTOR3 colorUp	= red * (pBuffer[coord(x-1, z, y+1)].metadata / 15.0f) + yellow *  (max(0.0f, pBuffer[coord(x-1, z, y+1)].metadata - 8.0f)  / 7.0f);
			BlockVertex face[] = 
			{
				{D3DXVECTOR3( -0.49f + _x,  0.5f + _y,  0.5f + _z),	uv[3], skylight[3], blocklight[3], colorUp},
				{D3DXVECTOR3( -0.49f + _x, -0.5f + _y,  0.5f + _z),	uv[1], skylight[1], blocklight[1], color},
				{D3DXVECTOR3( -0.49f + _x,  0.5f + _y, -0.5f + _z),	uv[2], skylight[2], blocklight[2], colorUp},
				{D3DXVECTOR3( -0.49f + _x, -0.5f + _y, -0.5f + _z),	uv[0], skylight[0], blocklight[0], color},
			};
			memcpy(pVertex + size, face, sizeof(face));
			size += 4;
		}

		if (pBuffer[coord(x, z-1, y+1)].id == bid) {
			D3DXVECTOR3 colorUp	= red * (pBuffer[coord(x, z-1, y+1)].metadata / 15.0f) + yellow *  (max(0.0f, pBuffer[coord(x, z+-1, y+1)].metadata - 8.0f)  / 7.0f);
			BlockVertex face[] = 
			{
				{D3DXVECTOR3( 0.5f + _x, -0.5f + _y, -0.49f + _z),	uv[3], skylight[3], blocklight[3], color},
				{D3DXVECTOR3( 0.5f + _x,  0.5f + _y, -0.49f + _z),	uv[1], skylight[1], blocklight[1], colorUp},
				{D3DXVECTOR3(-0.5f + _x, -0.5f + _y, -0.49f + _z),	uv[2], skylight[2], blocklight[2], color},
				{D3DXVECTOR3(-0.5f + _x,  0.5f + _y, -0.49f + _z),	uv[0], skylight[0], blocklight[0], colorUp},
			};
			memcpy(pVertex + size, face, sizeof(face));
			size += 4;
		}

		if (pBuffer[coord(x, z+1, y+1)].id == bid) {
			D3DXVECTOR3 colorUp	= red * (pBuffer[coord(x, z+1, y+1)].metadata / 15.0f) + yellow *  (max(0.0f, pBuffer[coord(x, z+1, y+1)].metadata - 8.0f)  / 7.0f);
			BlockVertex face[] = 
			{
				{D3DXVECTOR3( 0.5f + _x,  0.5f + _y, 0.49f + _z),	uv[3], skylight[3], blocklight[3], colorUp},
				{D3DXVECTOR3( 0.5f + _x, -0.5f + _y, 0.49f + _z),	uv[1], skylight[1], blocklight[1], color},
				{D3DXVECTOR3(-0.5f + _x,  0.5f + _y, 0.49f + _z),	uv[2], skylight[2], blocklight[2], colorUp},
				{D3DXVECTOR3(-0.5f + _x, -0.5f + _y, 0.49f + _z),	uv[0], skylight[0], blocklight[0], color},
			};
			memcpy(pVertex + size, face, sizeof(face));
			size += 4;
		}
	}
	*pSize = size;
	return 0;
}

byte genCrossBlock(int x, int z, int y, float _x, float _z, float _y, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	/* LIGHTVALUES */
	float skylight[4];
	float blocklight[4];

	byte bid = pBuffer[coord(x, z, y)].id;

	/*
	-x
	+-+---------+-+
	-z|0|         |1|
	+-+---------+-+
	| |         | |
	| |         | |
	| |         | |
	| |         | |
	+-+---------+-+
	|2|         |3|+z
	+-+---------+-+
	+x
	*/

	WORD size = 0;

	genLight(x, z, y+1, FACEUP, pBuffer, skylight, blocklight);

	D3DXVECTOR2 * uv = getBlockUV(bid, FACELEFT);

	//float meta = static_cast<float>(pBuffer[coord(x, z, y)].metadata);
	D3DXVECTOR3 color	= BiomeColor(pBuffer[coord(x, z, 0)].temperature, pBuffer[coord(x, z, 0)].humidity);	
	{
		BlockVertex face[] = 
		{
			{D3DXVECTOR3( -0.4f + _x,  0.5f + _y, -0.4f + _z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3( -0.4f + _x, -0.5f + _y, -0.4f + _z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(  0.4f + _x,  0.5f + _y,  0.4f + _z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(  0.4f + _x, -0.5f + _y,  0.4f + _z),	uv[0], skylight[0], blocklight[0], color},
		};
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}
	{
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(  0.4f + _x,  0.5f + _y,  0.4f + _z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(  0.4f + _x, -0.5f + _y,  0.4f + _z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3( -0.4f + _x,  0.5f + _y, -0.4f + _z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3( -0.4f + _x, -0.5f + _y, -0.4f + _z),	uv[0], skylight[0], blocklight[0], color},
		};
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}
	{
		BlockVertex face[] = 
		{
			{D3DXVECTOR3( -0.4f + _x,  0.5f + _y,  0.4f + _z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3( -0.4f + _x, -0.5f + _y,  0.4f + _z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(  0.4f + _x,  0.5f + _y, -0.4f + _z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(  0.4f + _x, -0.5f + _y, -0.4f + _z),	uv[0], skylight[0], blocklight[0], color},
		};
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}
	{
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(  0.4f + _x,  0.5f + _y, -0.4f + _z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(  0.4f + _x, -0.5f + _y, -0.4f + _z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3( -0.4f + _x,  0.5f + _y,  0.4f + _z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3( -0.4f + _x, -0.5f + _y,  0.4f + _z),	uv[0], skylight[0], blocklight[0], color},
		};
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}
	*pSize = size;
	return 0;
}

byte genLiquidBlock(int x, int z, int y, float _x, float _z, float _y, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	/* LIGHTVALUES */
	float skylight[4];
	float blocklight[4];

	byte bid = pBuffer[coord(x, z, y)].id;

	D3DXVECTOR3 min = D3DXVECTOR3(-0.5f + _x, -0.5f + _y, -0.5f + _z);

	/*
	-x
	+-+---------+-+
	-z|0|         |1|
	+-+---------+-+
	| |         | |
	| |         | |
	| |         | |
	| |         | |
	+-+---------+-+
	|2|         |3|+z
	+-+---------+-+
	+x
	*/
	D3DXVECTOR3 max[] = {
		D3DXVECTOR3( -0.5f + _x,  0.5f + _y, -0.5f + _z),
		D3DXVECTOR3( -0.5f + _x,  0.5f + _y,  0.5f + _z),
		D3DXVECTOR3(  0.5f + _x,  0.5f + _y, -0.5f + _z),
		D3DXVECTOR3(  0.5f + _x,  0.5f + _y,  0.5f + _z),
	};

	if (!pBuffer[coord(x, z, y+1)].liquid) {
		byte height[8] = {
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
			pBuffer[coord(x,z,y)].metaLo,
		};
		if (pBuffer[coord(x, z-1, y)].liquid) {
			if (pBuffer[coord(x, z-1, y+1)].liquid) {
				height[0] = 0xF;
			} else
				height[0] = pBuffer[coord(x,z-1,y)].metaLo;
		}
		if (pBuffer[coord(x-1, z, y)].liquid) {
			if (pBuffer[coord(x-1, z, y+1)].liquid) {
				height[1] = 0xF;
			} else
				height[1] = pBuffer[coord(x-1,z,y)].metaLo;
		}
		if (pBuffer[coord(x, z+1, y)].liquid) {
			if (pBuffer[coord(x, z+1, y+1)].liquid) {
				height[2] = 0xF;
			} else
				height[2] = pBuffer[coord(x,z+1,y)].metaLo;
		}
		if (pBuffer[coord(x+1, z, y)].liquid) {
			if (pBuffer[coord(x+1, z, y+1)].liquid) {
				height[3] = 0xF;
			} else
				height[3] = pBuffer[coord(x+1,z,y)].metaLo;
		}

		/* Diagonale */
		if (pBuffer[coord(x-1, z-1, y)].liquid) {
			if (pBuffer[coord(x-1, z-1, y+1)].liquid) {
				height[4] = 0xF;
			} else
				height[4] = max(height[4], pBuffer[coord(x-1,z-1,y)].metaLo);
		}
		if (pBuffer[coord(x-1, z+1, y)].liquid) {
			if (pBuffer[coord(x-1, z+1, y+1)].liquid) {
				height[5] = 0xF;
			} else
				height[5] = max(height[5], pBuffer[coord(x-1,z+1,y)].metaLo);
		}
		if (pBuffer[coord(x+1, z-1, y)].liquid) {
			if (pBuffer[coord(x+1, z-1, y+1)].liquid) {
				height[6] = 0xF;
			} else
				height[6] = max(height[6], pBuffer[coord(x+1,z-1,y)].metaLo);
		}
		if (pBuffer[coord(x+1, z+1, y)].liquid) {
			if (pBuffer[coord(x+1, z+1, y+1)].liquid) {
				height[7] = 0xF;
			} else
				height[7] = max(height[7], pBuffer[coord(x+1,z+1,y)].metaLo);
		}

		max[0].y -= 1.0f - max(height[4], max(height[0], height[1])) / 15.0f;
		max[1].y -= 1.0f - max(height[5], max(height[1], height[2])) / 15.0f;
		max[2].y -= 1.0f - max(height[6], max(height[0], height[3])) / 15.0f;
		max[3].y -= 1.0f - max(height[7], max(height[3], height[2])) / 15.0f;
	}


	WORD size = 0;

	if (pBuffer[coord(x-1, z, y)].face && ((pBuffer[coord(x-1, z, y)].id != bid))) {

		genLight(x-1, z, y, FACELEFT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACELEFT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(min.x, min.y, max[1].z),		uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x, max[0].y, min.z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, max[1].y, max[1].z),	uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x+1, z, y)].face && ((pBuffer[coord(x+1, z, y)].id != bid))) {

		genLight(x+1, z, y, FACERIGHT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACERIGHT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max[3].x, max[3].y, max[3].z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max[3].x, min.y, max[3].z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(max[2].x, max[2].y, min.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max[2].x, min.y, min.z),		uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z-1, y)].face && ((pBuffer[coord(x, z-1, y)].id != bid))) {

		genLight(x, z-1, y, FACEBACK, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEBACK);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max[2].x, max[2].y, min.z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max[2].x, min.y, min.z),		uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max[0].y, min.z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z+1, y)].face && ((pBuffer[coord(x, z+1, y)].id != bid))) {

		genLight(x, z+1, y, FACEFRONT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEFRONT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, max[1].z),		uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max[3].x, min.y, max[3].z),	uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x, max[1].y, max[1].z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max[3].x, max[3].y, max[3].z), uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if ((pBuffer[coord(x, z, y-1)].id != bid) && pBuffer[coord(x, z, y-1)].face) {
		genLight(x, z, y-1, FACEDOWN, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEDOWN);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max[2].x, min.y, min.z),		uv[1], skylight[1], blocklight[1], color},				
			{D3DXVECTOR3(min.x, min.y, max[1].z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max[3].x, min.y, max[3].z),	uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if ((pBuffer[coord(x, z, y+1)].id != bid)) {
		genLight(x, z, y+1, FACEUP, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEUP);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max[3].x, max[3].y, max[3].z), uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max[2].x, max[2].y, min.z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max[1].y, max[1].z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, max[0].y, min.z),		uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	*pSize = size;
	return 1;
}

byte genTorchBlock(int x, int z, int y, float _x, float _z, float _y, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	/* LIGHTVALUES */
	float skylight[4] = {
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
		g_LightLevels[pBuffer[coord(x, z, y)].skylight],
	};
	float blocklight[4] = {
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
		g_LightLevels[pBuffer[coord(x, z, y)].blocklight],
	};

	byte bid = pBuffer[coord(x, z, y)].id;

	/*
	-x
	+-+---------+-+
	-z|0|         |1|
	+-+---------+-+
	| |         | |
	| |         | |
	| |         | |
	| |         | |
	+-+---------+-+
	|2|         |3|+z
	+-+---------+-+
	+x
	*/
	D3DXVECTOR3 min = D3DXVECTOR3(-0.06f, -0.5f, -0.06f);
	D3DXVECTOR3 max = D3DXVECTOR3( 0.06f,  0.1f,  0.06f);
	D3DXMATRIX mat; D3DXMatrixIdentity(&mat);
	D3DXMATRIX trans; D3DXMatrixTranslation(&trans, _x, _y, _z);
	switch (pBuffer[coord(x, z, y)].metadata & FACEALL)
	{
	case FACEUP:	break;
	case FACEDOWN:	D3DXMatrixRotationZ(&mat,  D3DX_PI); break;
	case FACELEFT:	D3DXMatrixRotationZ(&mat,  D3DX_PI / 4); trans._41 += 0.2f; break;
	case FACERIGHT: D3DXMatrixRotationZ(&mat, -D3DX_PI / 4); trans._41 -= 0.2f; break;
	case FACEFRONT: D3DXMatrixRotationX(&mat,  D3DX_PI / 4); trans._43 -= 0.2f; break;
	case FACEBACK:	D3DXMatrixRotationX(&mat, -D3DX_PI / 4); trans._43 += 0.2f; break;
	default:
		break;
	}	
	mat = mat * trans;

	WORD size = 0;

	{
		//genLight(x-1, z, y, FACELEFT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACELEFT);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(min.x, min.y, max.z),		uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x, max.y, min.z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, max.y, max.z),	uv[3], skylight[3], blocklight[3], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	{

		//	genLight(x+1, z, y, FACERIGHT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACERIGHT);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x, max.y, max.z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x, min.y, max.z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(max.x, max.y, min.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x, min.y, min.z),	uv[0], skylight[0], blocklight[0], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	{

		//	genLight(x, z-1, y, FACEBACK, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEBACK);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x, max.y, min.z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x, min.y, min.z),		uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max.y, min.z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	{

		//	genLight(x, z+1, y, FACEFRONT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEFRONT);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, max.z),		uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max.x, min.y, max.z),	uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x, max.y, max.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x, max.y, max.z), uv[3], skylight[3], blocklight[3], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	{
		//	genLight(x, z, y-1, FACEDOWN, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEDOWN);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, min.z),			uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max.x, min.y, min.z),		uv[1], skylight[1], blocklight[1], color},				
			{D3DXVECTOR3(min.x, min.y, max.z),		uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x, min.y, max.z),	uv[3], skylight[3], blocklight[3], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	{
		//	genLight(x, z, y+1, FACEUP, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEUP);
		if ((bid == 91) && ((pBuffer[coord(x, z, y)].metadata & AKTIV) == 0)) {
			for (int i = 0; i < 4; i++) {
				uv[i].y += TEXTURETILE;
			}
		}
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x, max.y, max.z), uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x, max.y, min.z), uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max.y, max.z), uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, max.y, min.z), uv[0], skylight[0], blocklight[0], color},
		};
		for (int i = 0; i < 4; i++) {
			D3DXVec3TransformCoord(&face[i].Pos, &face[i].Pos, &mat);
		}
		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	*pSize = size;
	return 0;
}

byte genCactusBlock(int x, int z, int y, float _x, float _z, float _y, genBuffer * pBuffer, BlockVertex * pVertex, WORD * pSize) {
	/* LIGHTVALUES */
	float skylight[4];
	float blocklight[4];

	byte bid = pBuffer[coord(x, z, y)].id;

	D3DXVECTOR3 min = D3DXVECTOR3(-0.580f + _x, -0.5f + _y, -0.580f + _z);
	D3DXVECTOR3 max = D3DXVECTOR3( 0.580f + _x,  0.5f + _y,  0.580f + _z);
	/*
	-x
	+-+---------+-+
	-z|0|         |1|
	+-+---------+-+
	| |         | |
	| |         | |
	| |         | |
	| |         | |
	+-+---------+-+
	|2|         |3|+z
	+-+---------+-+
	+x
	*/

	WORD size = 0;

	if (pBuffer[coord(x-1, z, y)].face) {

		genLight(x-1, z, y, FACELEFT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACELEFT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x + 0.0725f, min.y, min.z),	uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(min.x + 0.0725f, min.y, max.z),	uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x + 0.0725f, max.y, min.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x + 0.0725f, max.y, max.z),	uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x+1, z, y)].face) {

		genLight(x+1, z, y, FACERIGHT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACERIGHT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x - 0.0725f, max.y, max.z),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x - 0.0725f, min.y, max.z),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(max.x - 0.0725f, max.y, min.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x - 0.0725f, min.y, min.z),	uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z-1, y)].face) {

		genLight(x, z-1, y, FACEBACK, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEBACK);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x, max.y, min.z + 0.0725f),	uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x, min.y, min.z + 0.0725f),	uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max.y, min.z + 0.0725f),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, min.y, min.z + 0.0725f),	uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z+1, y)].face) {

		genLight(x, z+1, y, FACEFRONT, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEFRONT);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, max.z - 0.0725f), uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max.x, min.y, max.z - 0.0725f), uv[1], skylight[1], blocklight[1], color},					
			{D3DXVECTOR3(min.x, max.y, max.z - 0.0725f), uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x, max.y, max.z - 0.0725f), uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z, y-1)].face) {
		genLight(x, z, y-1, FACEDOWN, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEDOWN);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(min.x, min.y, min.z),	uv[0], skylight[0], blocklight[0], color},
			{D3DXVECTOR3(max.x, min.y, min.z),	uv[1], skylight[1], blocklight[1], color},				
			{D3DXVECTOR3(min.x, min.y, max.z),	uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(max.x, min.y, max.z),	uv[3], skylight[3], blocklight[3], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	if (pBuffer[coord(x, z, y+1)].face) {
		genLight(x, z, y+1, FACEUP, pBuffer, skylight, blocklight);

		D3DXVECTOR2 * uv = getBlockUV(bid, FACEUP);
		D3DXVECTOR3 color = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
		BlockVertex face[] = 
		{
			{D3DXVECTOR3(max.x, max.y, max.z), uv[3], skylight[3], blocklight[3], color},
			{D3DXVECTOR3(max.x, max.y, min.z), uv[1], skylight[1], blocklight[1], color},
			{D3DXVECTOR3(min.x, max.y, max.z), uv[2], skylight[2], blocklight[2], color},
			{D3DXVECTOR3(min.x, max.y, min.z), uv[0], skylight[0], blocklight[0], color},
		};

		memcpy(pVertex + size, face, sizeof(face));
		size += 4;
	}

	*pSize = size;
	return 0;
}

/* BlockgenerationFunktions */
map<blocktype, BLOCKGEN> initFunction() {
	map<blocktype, BLOCKGEN> m;
	m[WATER]	= genLiquidBlock;
	m[LAVA]		= genLiquidBlock;
	m[90]		= genRedstonedust;
	m[91]		= genTorchBlock;
	m[40]		= genTorchBlock;
	m[15]		= genCrossBlock;
	m[17]		= genCrossBlock;
	m[18]		= genCactusBlock;
	return m;
};
const map<blocktype, BLOCKGEN> Block::generationMap = initFunction();

map<blocktype, BLOCKGEO> initGeometry() {
	map<blocktype, BLOCKGEO> m;
	return m;
};
     map<blocktype, BLOCKGEO> Block::geometryMap	= initGeometry();
/* BlockgenerationFunktions */
#endif

/* BLOCK UPDATE SECTION */

/*
Transfers water from the given Block* sourceBlock to the coordinates specified by the three coordinates.
The amount of water can be limited by maxdrain.
If permitEmpty is true, the sourceBlock can be emptied entirely (used for down-flowing water)

Will return true, if the sourceBlock(->metadata) was changed
*/
inline byte updateTransferWater(IWorld * world, Block* sourceBlock, int x, int z, int y, byte maxdrain, boolean permitEmpty) {
	bool update = 0;
	Block destinationBlock  = world->getBlock(x,z,y);
	//if (destinationBlock.blockID==AIR)
	if ((destinationBlock.blockID==AIR))// || (destinationBlock.status & SOFT))
	{
		byte drain = min(maxdrain, (permitEmpty ? sourceBlock->metaLo : (sourceBlock->metaLo) >> 1));
		if (drain > 0)
		{
			sourceBlock->metaLo		-= drain;

			Block newblock = {sourceBlock->blockID, 0, 0, drain + 240, 0 | LIQUID};
			if (newblock.blockID == LAVA)
				newblock.blockLight = 15;
			world->setBlock(x, z, y, newblock, UPDATE_GEOMETRY | UPDATE_LIGHT);
			update = 1;
		}
	}
	else if (((destinationBlock.blockID==WATER) && (sourceBlock->blockID == WATER)) ||
		((destinationBlock.blockID==LAVA) && (sourceBlock->blockID == LAVA)))
	{
		byte drain = min(maxdrain, sourceBlock->metaLo);
		if (!permitEmpty) drain = min(drain, abs(sourceBlock->metaLo - destinationBlock.metaLo)/2);
		drain = min(drain, 0xF - destinationBlock.metaLo);
		if (drain > 0)
		{
			sourceBlock->metaLo		-= drain;

			destinationBlock.metaLo	+= drain;
			destinationBlock.status = (destinationBlock.status & ~15) | (destinationBlock.metaLo / 12 + 1); // Update LightDampeningValue
			world->setBlock(x,z,y, destinationBlock, UPDATE_GEOMETRY);
			update = 1;
		}
	}
	else if ((destinationBlock.blockID==LAVA) && (sourceBlock->blockID == WATER))
	{
		byte drain = min(maxdrain, min(sourceBlock->metaLo, destinationBlock.metaHi ));

		if (drain > 0)
		{
			sourceBlock->metaLo		-= drain;// min(drain, destinationBlock.metaHi);

			destinationBlock.metaHi -= drain;// min(drain, destinationBlock.metaHi);

			if (destinationBlock.metaHi == 0) {
				destinationBlock = COBBLE_BLOCK;
				world->setBlock(x,z,y, destinationBlock, UPDATE_GEOMETRY | UPDATE_LIGHT);
			} else {
				world->setBlock(x,z,y, destinationBlock, 0x0);
			}
			update = 1;
		}
	}
	else if ((destinationBlock.blockID==WATER) && (sourceBlock->blockID == LAVA))
	{
		byte drain = min(maxdrain, min(sourceBlock->metaLo, destinationBlock.metaHi ));

		if (drain > 0)
		{
			sourceBlock->metaLo		-= drain;// min(drain, destinationBlock.metaHi);

			destinationBlock.metaHi -= drain;// min(drain, destinationBlock.metaHi);

			if (destinationBlock.metaHi == 0) {
				destinationBlock = STONE_BLOCK;
				world->setBlock(x,z,y, destinationBlock, UPDATE_GEOMETRY | UPDATE_LIGHT);
			} else {
				world->setBlock(x,z,y, destinationBlock, 0x0);
			}
			update = 1;
		}
	}
	return update;
};

byte updateLiquidBlock(int * px, int * pz, int * py, IWorld * world, Block useless, byte updateType, byte * ticks) {
	if ((updateType & BLOCKUPDATE) == 0) return 0;

	int x = *px;
	int z = *pz;
	int y = *py;

	Block* block = world->getpBlock(x,z,y);

	if (block == NULL) return 0;
	if (block->blockID == WATER) {
		*ticks = 1;
	} else {
		*ticks = 10;
	};

	byte update = 0;
	if ((update = updateTransferWater(world, block, x, z, y-1, 2, true)) == 0) // flow downwards
	{
		INTVECTOR3 vec3[] = {INTVECTOR3(-1,0,0),INTVECTOR3(1,0,0),INTVECTOR3(0,-1,0),INTVECTOR3(0,1,0)};
		int count = GetTickCount()%4;
		for (int i = 0; i < 4; i++)
		{
			int take = (count+i)%4;
			update |= updateTransferWater(world, block, x+vec3[take].x, z+vec3[take].z, y+vec3[take].y, 2, false); //flow sidewards
			if(world->getBlock(x+vec3[take].x, z+vec3[take].z, y+vec3[take].y).blockID == AIR &&
				(world->getBlock(x+vec3[take].x, z+vec3[take].z, y+vec3[take].y-1).blockID == AIR || world->getBlock(x+vec3[take].x, z+vec3[take].z, y+vec3[take].y-1).status & LIQUID))
				if (update |= updateTransferWater(world, block, x+vec3[take].x, z+vec3[take].z, y+vec3[take].y-1, 1, true)) {// Flow across an edge, diagonally downsidewards
					/*
					*px = x + vec3[take].x;
					*py = y + vec3[take].y - 1;
					*pz = z + vec3[take].z;
					*/
					world->delayedUpdateBlock(x+vec3[take].x, z+vec3[take].z, y+vec3[take].y-1, BLOCKUPDATE, *ticks);
				};//world->delayedUpdateBlock(x+vec3[take].x, z+vec3[take].z, y+vec3[take].y-1, *ticks);
		}
	}
	if (update)
	{
		Block setblock = *block;
		//setblock.status|=1;	if (setblock.metaLo < 7) setblock.status--; // Update LightDampeningValue
		if (block->metaLo == 0) {
			setblock = AIR_BLOCK;
			world->setBlock(x,z,y, setblock, UPDATE_GEOMETRY | UPDATE_LIGHT); 
		}
		else {
			setblock.status = (setblock.status & ~15) | (setblock.metaLo / 12 + 1);
			world->setBlock(x,z,y, setblock, 0x0); 
		}
	}
	return update;
}

byte updateLeafBlock(int * px, int * pz, int * py, IWorld * world, Block block, byte updateType, byte * ticks) {
	if ((updateType & BLOCKUPDATE) == 0) return 0;

	int x = *px;
	int z = *pz;
	int y = *py;
	bool update = 0;

	Block topBlock = world->getBlock(x,z,y+1);
	Block leftBlock = world->getBlock(x+1,z,y);
	Block rightBlock = world->getBlock(x-1,z,y);
	Block frontBlock = world->getBlock(x,z+1,y);
	Block backBlock = world->getBlock(x,z-1,y);
	Block downBlock = world->getBlock(x,z,y-1);
	if ((leftBlock.blockID == 10) || (rightBlock.blockID == 10) || (frontBlock.blockID == 10) ||
		(backBlock.blockID == 10) || (topBlock.blockID == 10) || (downBlock.blockID == 10)) {
			if (block.metaLo != 4) {
				block.metaLo = 4;
				world->setBlock(x, z, y, block);
			}
	} else {
		byte vitality = 0;
		if (leftBlock.blockID == 14) vitality	= max(vitality, leftBlock.metadata);
		if (rightBlock.blockID == 14) vitality	= max(vitality, rightBlock.metadata);
		if (frontBlock.blockID == 14) vitality	= max(vitality, frontBlock.metadata);
		if (backBlock.blockID == 14) vitality	= max(vitality, backBlock.metadata);
		if (topBlock.blockID == 14) vitality	= max(vitality, topBlock.metadata);
		if (downBlock.blockID == 14) vitality	= max(vitality, downBlock.metadata);

		if (vitality >= block.metaLo) {
			if (vitality > 0) {
				block.metaLo = vitality - 1;
				update = BLOCKUPDATE;
				*ticks = rand() % 100 + 30;
			}
		} else {
			block.metaLo = vitality;
		}

		if (block.metaLo == 0) {
			world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		} else {
			world->setBlock(x, z, y, block);
		}
	}
	return update;
}

byte updatePlantBlock(int * px, int * pz, int * py, IWorld * world, Block block, byte updateType, byte * ticks) {
	if ((updateType & BLOCKUPDATE) == 0) return 0;

	int x = *px;
	int z = *pz;
	int y = *py;
	bool update = 0;

	Block downBlock = world->getBlock(x,z,y-1);
	if ((downBlock.blockID == AIR) || (downBlock.status & LIQUID)) {
		world->setBlock(x, z, y, AIR_BLOCK, UPDATE_GEOMETRY | UPDATE_LIGHT);
		update = BLOCKUPDATE;
	}

	return update;
}

byte updateRedstoneDust(int * px, int * pz, int * py, IWorld * world, Block block, byte updateType, byte * ticks) {
	int x		= *px;
	int z		= *pz;
	int y		= *py;
	*ticks		= 0;
	byte update = 0;

	/* POWERED BENEATH/ABOVE */
	Block block1;
	if ((block1 = world->getBlock(x,z,y-1)).status & STRONGPOWERED ) {
		if ( block.metadata != 15)  {
			update			= STRONG_REDSTONEUPDATE;
			block.metadata	= 15;
		}		
		goto lUpdate;
	} /*else 	if (block1.status & SOLID) {
	  block1.status |= WEAKPOWERED;
	  world->setBlock(x,z,y-1, block1);
	  }*/
	if ( world->getBlock(x,z,y+1).status & STRONGPOWERED ) {
		if ( block.metadata != 15)  {
			update			= STRONG_REDSTONEUPDATE;
			block.metadata	= 15;
		}		
		goto lUpdate;
	}

	Block adjBlocks[] = {
		world->getBlock(x+1,z,y),
		world->getBlock(x-1,z,y),
		world->getBlock(x,z+1,y),
		world->getBlock(x,z-1,y),

		world->getBlock(x+1,z,y+1),
		world->getBlock(x-1,z,y+1),
		world->getBlock(x,z+1,y+1),
		world->getBlock(x,z-1,y+1),

		world->getBlock(x+1,z,y-1),
		world->getBlock(x-1,z,y-1),
		world->getBlock(x,z+1,y-1),
		world->getBlock(x,z-1,y-1),
	};

	byte buff = 0;
	for (int i = 0; i < 4; i++) {
		if (adjBlocks[i].blockID == 90) {
			buff = max(buff, adjBlocks[i].metadata - 1);
			/* TORCH ON SIDE */
		} else if (adjBlocks[i].status & STRONGPOWERED) {
			if ( block.metadata != 15)  {
				update			= STRONG_REDSTONEUPDATE;
				block.metadata	= 15;
			}		
			goto lUpdate;
			/* VERTICAL-UP POWERED */
		} else if (adjBlocks[i].status & SOLID) {
			if (adjBlocks[i + 4].blockID == 90) {
				buff = max(buff, adjBlocks[i + 4].metadata - 1);
			}
		}
	}
	/*  VERTICAL-DOWN POWERED */
	if (world->getBlock(x,z,y-1).status & SOLID) {
		for (int i = 8; i < 12; i++) {
			if (adjBlocks[i].blockID == 90) {
				buff = max(buff, adjBlocks[i].metadata - 1);
			} 
		}
	} 

	if (buff != block.metadata) {	
		update = STRONG_REDSTONEUPDATE;
	}
	block.metadata	= buff;

lUpdate:
	if (update) {
		block.blockLight = max(block.blockLight, block.metadata / 5);
		world->setBlock(x, z, y, block, UPDATE_GEOMETRY | UPDATE_LIGHT);
	}
	if (updateType & BLOCKUPDATE)
		update = STRONG_REDSTONEUPDATE;
	return update;
}

byte updateRedstoneTorch(int * px, int * pz, int * py, IWorld * world, Block block, byte updateType, byte * ticks) {
	*ticks		= 1;
	int x		= *px;
	int z		= *pz;
	int y		= *py;
	byte update = 0;
	bool on		= true;
	if (updateType & BLOCK_REMOVED) {
		on		= false;
	} else {
		switch (block.metadata & FACEALL)
		{
		case FACEUP: {	
			if (world->getBlock(x,z,y-1).status & POWERED) {
				on = false;
			}
					 }
					 break;
		case FACEDOWN: {
			if (world->getBlock(x,z,y+1).status & POWERED) {
				on = false;
			}
					   }
					   break;
		case FACELEFT: {
			if (world->getBlock(x+1,z,y).status & POWERED) {
				on = false;
			}
					   }
					   break;
		case FACERIGHT:	{
			if (world->getBlock(x-1,z,y).status & POWERED) {
				on = false;
			}
						}
						break;
		case FACEFRONT: {	
			if (world->getBlock(x,z-1,y).status & POWERED) {
				on = false;
			}
						}
						break;
		case FACEBACK: {
			if (world->getBlock(x,z+1,y).status & POWERED) {
				on = false;
			}
					   }
					   break;
		}	
	}

	if (((block.metadata & AKTIV) == AKTIV) != on) {
		update = STRONG_REDSTONEUPDATE;

		if (on) {
			block.blockLight = 7;
			block.metadata |= AKTIV;
			block.status   |= POWERED;
		} else {
			block.blockLight = 0;
			block.metadata &= ~AKTIV;
			block.status   &= ~POWERED;
		}

		Block * block1;
		if (block.metadata & FACEDOWN) {
			if (block1 = world->getpBlock(x, z, y-1)) {
				if (block1->status & SOLID) 
					if (on)
						block1->status |= POWERED;
					else
						block1->status &= ~POWERED;
			}
		} else if (block1 = world->getpBlock(x, z, y+1)) {
			if (block1->status & SOLID)
				if (on)
					block1->status |= POWERED;
				else
					block1->status &= ~POWERED;
		}
	}

	if (update) {
		world->setBlock(x, z, y, block, UPDATE_GEOMETRY | UPDATE_LIGHT);
	}

	//update = STRONG_REDSTONEUPDATE;
	return update;
}

byte updateSolidBlock(int * px, int * pz, int * py, IWorld * world, Block block, byte updateType, byte * ticks) {
	if (updateType & STRONG_REDSTONEUPDATE) {
		/*
		*ticks		= 0;
		int x		= *px;
		int z		= *pz;
		int y		= *py;
		block.status &= ~POWERED;
		world->setBlock(x, z, y, block, 0);*/
		return WEAK_REDSTONEUPDATE;
	} else
		return 0;
}

/* BlockupdateFunktions */
map<blocktype, BLOCKUPD> initUpdate() {
	map<blocktype, BLOCKUPD> m;
	m[WATER]	= updateLiquidBlock;
	m[LAVA]		= updateLiquidBlock;
	m[14]		= updateLeafBlock;
	m[15]		= updatePlantBlock;
	m[17]		= updatePlantBlock;

	m[90]		= updateRedstoneDust;
	m[91]		= updateRedstoneTorch;

	m[254]		= updateSolidBlock;
	return m;
};
const map<blocktype, BLOCKUPD> Block::updateMap = initUpdate();
/* BlockupdateFunktions */